package com.gjy.design.strategy.compression;

import net.jpountz.lz4.LZ4FrameInputStream;
import net.jpountz.lz4.LZ4FrameOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-11-06 14:50:45
 */
public class TarLz4CompressionStrategy implements CompressionStrategy {

    @Override
    public void compress(File[] source, File target) throws IOException {
        if (source == null || source.length == 0) {
            throw new IllegalArgumentException("源文件/文件夹数组不能为空");
        }
        if (source.length > 1) {
            System.err.println("警告: Lz4格式不支持压缩多个文件到单个归档。将只处理第一个源文件: " + source[0].getAbsolutePath());
        }

        File fileToCompress = source[0];
        if (fileToCompress.isDirectory()) {
            throw new UnsupportedOperationException("Lz4不支持压缩文件夹。");
        }

        try (TarArchiveOutputStream tar = new TarArchiveOutputStream(new LZ4FrameOutputStream(Files.newOutputStream(target.toPath())))) {
            String absolutePath = fileToCompress.getAbsolutePath();
            Path sourcePath = Paths.get(absolutePath);
            TarArchiveEntry entry = new TarArchiveEntry(absolutePath);

            entry.setSize(Files.size(sourcePath));
            tar.putArchiveEntry(entry);
            Files.copy(sourcePath, tar);
            tar.closeArchiveEntry();
        }

    }

    @Override
    public void decompress(File source, File target) throws IOException {
        if (!source.isFile()) {
            throw new IllegalArgumentException("源文件必须是文件，而不是目录");
        }
        if (target.exists() && target.isDirectory()) {
            // 如果目标是目录，将解压后的文件放在该目录下
            File decompressedFile = new File(target, getDecompressedFileName(source.getName()));
            decompressToFile(source, decompressedFile);
        } else if (target.exists() || !target.isDirectory()) {
            // 如果目标是文件或不存在的文件路径，直接解压到该文件
            decompressToFile(source, target);
        } else {
            throw new IOException("目标路径无效，已存在同名目录: " + target.getAbsolutePath());
        }
    }

    private void decompressToFile(File source, File target) throws IOException {
        File parent = target.getParentFile();
        if (parent != null && !parent.exists()) {
            parent.mkdirs();
        }
        try (TarArchiveInputStream tar = new TarArchiveInputStream(new LZ4FrameInputStream(Files.newInputStream(source.toPath())))) {
            TarArchiveEntry e;
            while ((e = tar.getNextEntry()) != null) {
                Path out = Paths.get(e.getName());
                if (e.isDirectory()) {
                    Files.createDirectories(out);
                } else {
                    Files.copy(tar, out, StandardCopyOption.REPLACE_EXISTING);
                }
            }
        }

    }

    private String getDecompressedFileName(String snappyFileName) {
        if (snappyFileName.toLowerCase().endsWith(".lz4")) {
            return snappyFileName.substring(0, snappyFileName.length() - ".lz4".length());
        }
        return snappyFileName + ".decompressed";
    }

}
